package net.wicp.tams.common;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.collections.Predicate;
import org.apache.commons.lang3.Validate;

import com.alibaba.fastjson.JSONObject;

import lombok.extern.slf4j.Slf4j;
import net.wicp.tams.common.apiext.ClassLoaderPlugin;
import net.wicp.tams.common.apiext.IOUtil;

/***
 * 
 * @author 偏锋书生
 *
 */
@Slf4j
public class Plugin {

	private ClassLoaderPlugin load;

	// private final Map<String, String> params;
	private final String parentClassName;// "net.wicp.tams.duckula.plugin.IReceive"

	private final Map<String, Class<?>> allClassmap = new HashMap<>();

	private final List<String> excludes = new ArrayList<>();

	private final List<String> includes = new ArrayList<>();

	public Plugin(String dirpath, String parentClassName, ClassLoader parent) {
		Validate.notBlank(dirpath, "插件所在的路径必须传　");
		load = new ClassLoaderPlugin(dirpath, parent);
		this.parentClassName = parentClassName;
	}

	public Plugin(String dirpath, String parentClassName, ClassLoader parent, List<String> includes,
			List<String> excludes) {
		this(dirpath, parentClassName, parent);
		if (CollectionUtils.isNotEmpty(includes)) {
			this.includes.addAll(includes);
		}
		if (CollectionUtils.isNotEmpty(excludes)) {
			this.excludes.addAll(excludes);
		}
	}

	public ClassLoaderPlugin getLoad() {
		return load;
	}

	public Class<?> loadSingle() {
		try {
			Map<String, Class<?>> classes = loadClasses();
			if (MapUtils.isEmpty(classes) || classes.size() > 1) {
				log.error(" {} 存在２个实现类,请检查代码", parentClassName);
				throw new IllegalArgumentException("recivers error");
			}
			Class<?> calssz = classes.values().iterator().next();
			return calssz;// (IReceive) calssz.newInstance();
		} catch (Exception e) {
			log.info("load receive is error", e);
			throw new RuntimeException("load receive is error");
		}
	}

	public Class<?> loadSingleByClassName(String className) {
		Map<String, Class<?>> classes = loadClasses();
		if (classes.containsKey(className)) {
			return classes.get(className);
		} else {
			try {
				if (IOUtil.isSubClass(className, parentClassName, load.getPool())) {
					Class<?> calssz = load.loadClass(className);
					allClassmap.put(className, calssz);
					return calssz;
				}
			} catch (Exception e) {
				log.error("类" + className + "没有找到", e);
			}

			return null;
		}

	}

	public synchronized void refresh() {
		allClassmap.clear();
	}

	private synchronized Map<String, Class<?>> loadClasses() {
		if (MapUtils.isNotEmpty(allClassmap)) {
			return allClassmap;
		}
		try {
			Set<String> subs = IOUtil.findSubClassByJars(parentClassName, 5, load.getJars(), load.getPool());
			if (CollectionUtils.isNotEmpty(excludes)) {
				CollectionUtils.filter(subs, new Predicate() {
					@Override
					public boolean evaluate(Object object) {
						return !excludes.contains(object);
					}
				});
			}

			if (CollectionUtils.isNotEmpty(includes)) {
				CollectionUtils.filter(subs, new Predicate() {
					@Override
					public boolean evaluate(Object object) {
						return includes.contains(object);
					}
				});
			}

			Map<String, Class<?>> retmap = new HashMap<>();
			for (String sub : subs) {
				Class<?> calssz = load.loadClass(sub);
				retmap.put(sub, calssz);
			}
			allClassmap.putAll(retmap);
			return retmap;
		} catch (ClassNotFoundException e) {
			log.info("the recicer is error", e);
			throw new RuntimeException("have no recicer");
		} catch (Exception e) {
			log.info("load receive is error", e);
			throw new RuntimeException("load receive is error");
		}
	}

	public Object newObject(Map<String, String> params) {
		try {
			return loadSingle().getConstructor(Map.class).newInstance(params);
		} catch (Exception e) {
			log.error("创建object失败", e);
			return null;
		}
	}

	public Object newObject(JSONObject params) {
		try {
			return loadSingle().getConstructor(JSONObject.class).newInstance(params);
		} catch (Exception e) {
			log.error("创建object失败", e);
			return null;
		}
	}

	public Object newObject() {
		try {
			return loadSingle().newInstance();
		} catch (Exception e) {
			log.error("创建object失败", e);
			return null;
		}
	}

}
